#include "StompedReality/Core/Graphics/Windows/WGLRenderSystem.h"
#include "StompedReality/Core/IGame.h"
#include <assert.h>
namespace StompedReality
{
namespace Graphics
{
bool WGLRenderSystem::m_Close = true;
static WGLRenderSystem* rs = 0;
WGLRenderSystem::WGLRenderSystem( )
{
  this->m_HRC = 0;
  this->m_HDC = 0;
  this->m_HWND = 0;
  this->m_HInstance = 0;
  m_Close = true;
  rs = this;
}

WGLRenderSystem::~WGLRenderSystem( )
{
#ifdef DEBUG
  std::cout << "info\t[RenderSystem]\t[Destructor]" << std::endl;
#endif
  this->CloseWindow( );
}

HDC WGLRenderSystem::GetHDC( )
{
  return this->m_HDC;
}

LRESULT CALLBACK WGLRenderSystem::WndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
  switch ( uMsg )        // Check For Windows Messages
  {
  case WM_CLOSE:
    m_Close = true;
  case WM_SIZE:
    int w = LOWORD( lParam );
    int h = HIWORD( lParam );
    rs->Resize( w, h );
  }
  return DefWindowProc ( hWnd, uMsg, wParam, lParam );
}

bool WGLRenderSystem::InitWindow ( int width, int height, bool fullscreen, const char* title )
{
  GLuint PixelFormat;
  WNDCLASS wc;
  DWORD dwExStyle;
  DWORD dwStyle;
  RECT WindowRect;
  WindowRect.left = ( long ) 0;
  WindowRect.right = ( long ) width;
  WindowRect.top = ( long ) 0;
  WindowRect.bottom = ( long ) height;
  m_HInstance   = GetModuleHandle ( NULL );
  wc.style   = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  wc.lpfnWndProc  = ( WNDPROC ) WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance  = m_HInstance;
  wc.hIcon   = LoadIcon ( NULL, IDI_WINLOGO );
  wc.hCursor   = LoadCursor ( NULL, IDC_ARROW );
  wc.hbrBackground = NULL;
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = "OpenGL";
  if ( !RegisterClass ( &wc ) )
  {
    return FALSE;
  }
  dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_ACCEPTFILES;
  dwStyle = WS_OVERLAPPEDWINDOW;
  AdjustWindowRectEx ( &WindowRect, dwStyle, FALSE, dwExStyle );

  // Create The Window
  if ( !( m_HWND = CreateWindowEx ( dwExStyle,
                                    "OpenGL",
                                    title,
                                    dwStyle |  WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
                                    0, 0,
                                    WindowRect.right - WindowRect.left,
                                    WindowRect.bottom - WindowRect.top,
                                    NULL,
                                    NULL,
                                    m_HInstance,
                                    NULL ) ) )
  {
    return false;
  }
  static PIXELFORMATDESCRIPTOR pfd =
  {
    sizeof ( PIXELFORMATDESCRIPTOR ),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,
    24,
    0, 0, 0, 0, 0, 0,
    0,
    0,
    0,
    0, 0, 0, 0,
    16,
    0,
    0,
    PFD_MAIN_PLANE,
    0,
    0, 0, 0
  };
  if ( !( m_HDC = GetDC ( m_HWND ) ) ||
       !( PixelFormat = ChoosePixelFormat ( m_HDC, &pfd ) ) ||
       !SetPixelFormat ( m_HDC, PixelFormat, &pfd ) ||
       !( m_HRC = wglCreateContext ( m_HDC ) ) ||
       !wglMakeCurrent ( m_HDC, m_HRC ) )
  {
    return false;
  }
  ShowWindow ( m_HWND, SW_SHOW );
  SetForegroundWindow ( m_HWND );
  SetFocus ( m_HWND );
  m_Close = false;
  return true;
}

bool WGLRenderSystem::CloseWindow( )
{
  if ( m_HRC )
  {
    m_HRC = NULL;
  }
  if ( m_HDC && !ReleaseDC ( m_HWND, m_HDC ) )
  {
    m_HDC = NULL;
  }
  if ( m_HWND && !DestroyWindow ( m_HWND ) )
  {
    m_HWND = NULL;
  }
  if ( !UnregisterClass ( "OpenGL", m_HInstance ) )
  {
    m_HInstance = NULL;
  }
  this->m_Close = true;
  return true;
}

bool WGLRenderSystem::InitGLExtensions( )
{
  // get procedures
  GLExtensions::glGenBuffersARB = ( PFNGLGENBUFFERSARBPROC ) wglGetProcAddress ( "glGenBuffersARB" );
  GLExtensions::glBindBufferARB = ( PFNGLBINDBUFFERARBPROC ) wglGetProcAddress ( "glBindBufferARB" );
  GLExtensions::glBufferDataARB = ( PFNGLBUFFERDATAARBPROC ) wglGetProcAddress ( "glBufferDataARB" );
  GLExtensions::glDeleteBuffersARB = ( PFNGLDELETEBUFFERSARBPROC ) wglGetProcAddress ( "glDeleteBuffersARB" );

  // check procedures
  GLExtensions::glInitialized = GLExtensions::glGenBuffersARB != 0 &&
    GLExtensions::glBindBufferARB != 0 &&
    GLExtensions::glBufferDataARB != 0 &&
    GLExtensions::glDeleteBuffersARB != 0;
  if ( GLExtensions::glInitialized )
  {
#ifdef DEBUG
    std::cout << "info\t[RenderSystem]\t[initGLExtensions]" << std::endl;
#endif
    return true;
  }
  else
  {
#ifdef DEBUG
    std::cout << "error\t[RenderSystem]\t[initGLExtensions]\t[failed]" << std::endl;
#endif
    return false;
  }
}

bool WGLRenderSystem::IsWindowOpen( )
{
  return !m_Close;
}

void WGLRenderSystem::SwapBuffer ( )
{
  SwapBuffers ( this->m_HDC );
}

void* WGLRenderSystem::GetDisplayPointer( ) {
  return this->m_HDC;
};

}
}